package edu.isistan.genetic.querymutator;

import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Vector;

import edu.isistan.genetic.operators.*;
import edu.isistan.genetic.representations.Individual;
import edu.isistan.metamodel.Interface;
import edu.isistan.parser.JavaParser;


public class QueryMutator {
	MutationProcess mutationProcess;
	Individual query;
	private String mutatedQueriesDestinationFolder;
	
	public QueryMutator() {
		// TODO Auto-generated constructor stub
	}

	public final Individual getQuery() {
		return query;
	}

	public final void setQuery(Individual query) {
		this.query = query;
	}

	public final MutationProcess getMutationProcess() {
		return mutationProcess;
	}

	public final void setMutationProcess(MutationProcess mutationProcess) {
		this.mutationProcess = mutationProcess;
	}
	
	public Vector<Individual> mutate(int resultSetSize){
		Vector<Individual> individuals=new Vector<Individual>();
		for (int i = 0; i < resultSetSize; i++) {
			individuals.add(mutationProcess.mutate(new Individual(query)));
		}
		return individuals;
	}
	
	private void generateJavaFile(Vector<Individual> individuals){
		StringBuffer sb=new StringBuffer();
		for (int i = 0; i < individuals.size(); i++) {
			sb=new StringBuffer("public class MutatedQuery"+ i +" { \n " + individuals.elementAt(i) + " }");
			try {
				BufferedWriter out = new BufferedWriter(new FileWriter(this.mutatedQueriesDestinationFolder+"/MutatedQuery"+i+".java"));
				out.write(sb.toString());
				out.close();
			}
			catch (IOException e){
				System.err.println("Error generating file " + e.getMessage() );
			}
		}
		
		
	}
	
	public void executeFromConfigurationProperties(String filePath){
		Properties prop = new Properties();
		JavaParser p = new JavaParser();
		Interface interace ;
		Vector<Operator> parametersOperators=new Vector<Operator>();
		Vector<Operator> returningValuesOperators=new Vector<Operator>();
		Vector<Double> parametersProbability=new Vector<Double>();
		Vector<Double> returningProbability=new Vector<Double>();
		MutationSimpleProcess mutationProcess;
				 
    	try {
            prop.load(new FileInputStream(filePath));
            //String properties
            String queryClassPath= prop.getProperty("queryClassPath");
    		
            interace = p.getMetamodel(queryClassPath);	
    		this.setQuery(new Individual(interace));
            
    		this.mutatedQueriesDestinationFolder= prop.getProperty("mutatedQueriesDestinationFolder");
    		   		

    		//Numeric properties
    		int numberOfMutatedQueries= Integer.parseInt(prop.getProperty("numberOfMutatedQueries"));
    		double mutationProbability=Double.parseDouble(prop.getProperty("mutationProbability"));
    		double parametersUpCastingOperator=Double.parseDouble(prop.getProperty("parametersUpCastingOperator"));
    		double parametersSuperTypeOperator=Double.parseDouble(prop.getProperty("parametersSuperTypeOperator"));
    		double parametersCollectionsOperator=Double.parseDouble(prop.getProperty("parametersCollectionsOperator"));
    		double parametersEncapsulateOperator=Double.parseDouble(prop.getProperty("parametersEncapsulateOperator"));
    		double parametersFlattenOperator=Double.parseDouble(prop.getProperty("parametersFlattenOperator"));
    		if (parametersFlattenOperator > 0){
    			parametersOperators.add(new Flatten());
    			parametersProbability.add(parametersFlattenOperator);
    		}
    		if (parametersCollectionsOperator > 0){
    			parametersOperators.add(new Collections());
    			parametersProbability.add(parametersCollectionsOperator);
    		}
    		if (parametersEncapsulateOperator > 0){
    			parametersOperators.add(new Encapsulate());
    			parametersProbability.add(parametersEncapsulateOperator);
    		}
    		if (parametersUpCastingOperator > 0){
    			parametersOperators.add(new UpCasting("int","long"));
    			parametersProbability.add(parametersUpCastingOperator);
    			parametersOperators.add(new UpCasting("int","double"));
    			parametersProbability.add(parametersUpCastingOperator);
    			parametersOperators.add(new UpCasting("long","float"));
    			parametersProbability.add(parametersUpCastingOperator);
    			parametersOperators.add(new UpCasting("long","double"));
    			parametersProbability.add(parametersUpCastingOperator);
    		}
    		if (parametersSuperTypeOperator > 0){
    			parametersOperators.add(new SuperType());
    			parametersProbability.add(parametersSuperTypeOperator);
    		}
    		
    		

    		double returnTypeUpCastingOperator=Double.parseDouble(prop.getProperty("returnTypeUpCastingOperator"));
    		double returnTypeSuperTypeOperator=Double.parseDouble(prop.getProperty("returnTypeSuperTypeOperator"));
    		double returnTypeCollectionsOperator=Double.parseDouble(prop.getProperty("returnTypeCollectionsOperator"));
    		
    		if (returnTypeUpCastingOperator > 0){
    			returningValuesOperators.add(new UpCasting("int","long"));
    			returningProbability.add(returnTypeUpCastingOperator);
    			returningValuesOperators.add(new UpCasting("int","double"));
    			returningProbability.add(returnTypeUpCastingOperator);
    			returningValuesOperators.add(new UpCasting("long","float"));
    			returningProbability.add(returnTypeUpCastingOperator);
    			returningValuesOperators.add(new UpCasting("long","double"));
    			returningProbability.add(returnTypeUpCastingOperator);
    		}
    		if (returnTypeCollectionsOperator > 0){
    			returningValuesOperators.add(new Collections());
    			returningProbability.add(returnTypeCollectionsOperator);
    		}
    		if (returnTypeSuperTypeOperator > 0){
    			returningValuesOperators.add(new SuperType());
    			returningProbability.add(returnTypeSuperTypeOperator);
    		}
    		if (prop.getProperty("mutationProcess").contains("probabilitybased"))
    			mutationProcess=new MutationProbabilityBased(parametersOperators,returningValuesOperators,mutationProbability,parametersProbability,returningProbability);
    			
    		else
    			mutationProcess=new MutationSimpleProcess(parametersOperators,returningValuesOperators,mutationProbability);
    		this.setMutationProcess(mutationProcess);
    		generateJavaFile(this.mutate(numberOfMutatedQueries));
 
    	} catch (IOException ex) {
    		System.err.println("Error: "+ ex.getMessage());
        }
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("Start process");
		QueryMutator querymutator= new QueryMutator();
		querymutator.executeFromConfigurationProperties(args[0]);
		System.out.println("End process");
	}

}
